package com.ryujung.thread;

import java.util.LinkedList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolDemo {
    // create a pool with 5 core size,10 max size ,20 queue size ,and deny strategy
    public static ThreadPoolExecutor createThreadPool() {
        // ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5,
        // TimeUnit.SECONDS,
        // new ArrayBlockingQueue<Runnable>(20), new
        // ThreadPoolExecutor.CallerRunsPolicy());
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(20), new ThreadPoolExecutor.DiscardOldestPolicy());
        return threadPoolExecutor;
    }

    // generate task for plus counter from 0 to 5
    public static synchronized Runnable generateTask(int taskID) {
        return () -> {
            try {
                // for (int i = 0; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + " is execute taskID: " + taskID);
                // + ", current value:" + i);
                Thread.sleep(1_000L);
                // }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };
    }

    /**
     * use threadpool execute the List of task which is generate by method above
     * 
     * Conclusion:
     * when tasks coming ->
     * first: -> core size threads
     * then: -> queue(core thread all busy,queue not full)
     * then: -> create thread to max pool size(core thread is busy,queue is full)
     * then: -> execute rejection policy
     */
    public static void main(String[] args) throws InterruptedException {
        LinkedList<Runnable> taskList = new LinkedList<Runnable>();
        ThreadPoolExecutor threadPool = createThreadPool();

        // When the task count less than thread pool's core size
        // int TaskCount = threadPool.getCorePoolSize();

        // When the task count equals to core size + queue's capacity
        // int taskCount = threadPool.getCorePoolSize() + threadPool.getQueue().remainingCapacity() ;

        // When thr task count euquals max size + queue's capacity
        // int taskCount = threadPool.getMaximumPoolSize() + threadPool.getQueue().remainingCapacity();

        // When thr task count more than max size + queue's capacity
        int taskCount = threadPool.getMaximumPoolSize() + threadPool.getQueue().remainingCapacity() + 5;

        System.out.println("current taskCount will be:" + taskCount);
        for (int i = 0; i < taskCount; i++) {
            taskList.add(generateTask(i));
        }

        for (int i = 0; i < taskList.size(); i++) {
            threadPool.execute(taskList.get(i));
        }
        System.out.println("added all tasks and current active count: " + threadPool.getActiveCount());

        // make sure the threadpool close gracefully
        threadPool.shutdown();
        threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);

        System.out.println("total finished task count:" + threadPool.getCompletedTaskCount());
        System.exit(0);
    }
}
